package com.example.video.thread;

import com.example.video.entity.Account;
import com.example.video.entity.ResponseData;
import com.example.video.entity.Video;
import com.example.video.service.impl.AccountServiceImpl;
import com.example.video.service.impl.VideoServiceImpl;
import com.example.video.util.download.DownTask;
import com.example.video.util.download.FileUtil;
import com.example.video.util.HHdata;
import lombok.extern.slf4j.Slf4j;

import java.util.Stack;
import java.util.UUID;

/**
 * 线程类，用于执行请求和下载
 */
@Slf4j
public class ResThread implements Runnable {
    private static final Stack<ResponseData.Post> responseStack = new Stack<>();
    private static final Stack<String> cursorStack = new Stack<>();

    private final HHdata hHdata;
    private Account account;
    private String next_cursor;
    private  final  AccountServiceImpl accountService;
    private final VideoServiceImpl videoService;
    private final DownTask downloader;
    private final String downLoadPath;
    private final String serverUrl;

    /**
     * 线程初始化
     */
    public ResThread(HHdata hHdata, Account account, String next_cursor, DownTask downloader) {
        this.hHdata = hHdata;
        this.account = account;
        this.next_cursor = next_cursor;
        this.accountService = hHdata.getAccountService();
        this.videoService = hHdata.getVideoService();
        this.downloader = downloader;
        this.downLoadPath = hHdata.getDownLoadPath();
        this.serverUrl = hHdata.getServerUrl();

//            log.info("downloadTask - > TaskThread -> msg : 开启任务线程");
    }

    /**
     * 使用栈来实现先下载最早发布视频
     */
    @Override
    public void run() {
        log.info("ResTread -> run -> msg: 线程进行");
        // 获取数据，压入栈内
        // 要考虑如果是更新数据的话，遇到数据库中有数据的，则不进行下载。并退出
        // 如果是更新数据，传来的cursor
        int total = 0;
        if(account.getTotal() != null){
            total = account.getTotal();
            log.info("ResThread -> run -> msg: 数据库中有数据 total = "+total);
        }
        // 数据库中是否已经存有数据的标志
        int flag = 0;
        int breakFlag = 0;
        String avatorUrl = "";
        String userName = "";
        while (true)
        {
            log.info("ResThread -> run -> msg: 获取数据");



            ResponseData result = hHdata.requestData(account.getUrl(), next_cursor).getData();
//            log.info("ResThread -> run -> msg: result = " +result);
            ResponseData.Data data = result.getData();


            if("".equals(userName)  ){
                if(data.getUser().getUsername() != null){
                    userName = data.getUser().getUsername();
                }else {
                    userName = UUID.randomUUID().toString();
                }
            }
            if("".equals(avatorUrl) && data.getUser().getAvatar() != null){
                log.info("ResThread -> run -> msg: 下载头像 = " +serverUrl + account.getName() + account.getName()+".jpg");
                FileUtil.downloadImage(data.getUser().getAvatar(), downLoadPath + account.getName() + account.getName()+".jpg");
                avatorUrl = serverUrl + account.getName() + account.getName()+".jpg";
            }

            // 进行处理
            total += data.getPosts().size();
            log.info("ResThread -> run -> msg: 获取总数 = " +data.getPosts().size());
            log.info("ResThread -> run -> msg: 总数plus = " +total);
            for ( int i =0; i<data.getPosts().size(); i++) {

                ResponseData.Post post = data.getPosts().get(i);
                // 若无id
                // 5.5 快手、b站的资源url中，最后一个/后的资源可能为资源id，使用这个   4.30 新增 若无id则创建一个id
                // eg. 快手： http://111.67.199.184:8123/video/goto/1714815866406.mp4?sign=nnuV-ofv9VN2Rjz2QbPiDpOlPmPWf
                // b站: http://upos-sz-mirror08c.bilivideo.com/upgcxcode/48/75/1525307548/1525307548-1-192.mp4?e=ig8eux
                if(post.getId() == null || "".equals(post.getId()) ){
                    // 5.5 注释，换成使用资源url里的id
                    // post.setId(MD5Utils.encryptMD5(account.getUrl() + next_cursor + i + post.getText() )) ;
                    String url = post.getMedias().get(0).getResource_url();
                    int lastSlashIndex = url.lastIndexOf('/');
                    String extractedString = url.substring(lastSlashIndex + 1, url.lastIndexOf('.'));
                    post.setId(extractedString);
                }else{
                    // 如果 url 为Instagram，则判断是否有 _ 有就去掉下划线和下划线后的。
                    if( account.getUrl().contains("instagram") && post.getId().contains("_") ){
                        post.setId( post.getId().split("_")[0] );
                    }
                }

                Video video = videoService.getItemByResourceIdAndAccountId(post.getId(), account.getId());

                // 若数据库有数据，total减1，设置flag标志为1，若已经保存数据库但还未下载，则存入
                if(video != null ){
                    flag = 1;
                    total --;
                    if(video.getStatus() != 0){
                        continue;
                    }
                }else{
                    log.info("ResThread -> run -> msg: 数据库中无数据，不执行total--");
                }

                responseStack.push(post);
                cursorStack.push(next_cursor);
            }

            next_cursor = result.getData().getNext_cursor();

            // 如果不是第一次请求这个数据，则可能是后续需要重新请求，则再进行一次请求就退出
            if("no_more".equals(result.getData().getNext_cursor()) || breakFlag == 1){
                break;
            }
            if(flag == 1){
                breakFlag = 1;
            }
        }
        account.setName(userName);
        account.setTotal(total);
        account.setAvatarUrl(avatorUrl);

        // 从栈顶取出数据，并进行下载，每次下载保存account到数据库，以防止程序异常退出后，数据重新下载
        while(!responseStack.isEmpty()){
            ResponseData.Post temp = responseStack.pop();
            String now_cursor = cursorStack.pop();
            downloader.addTask(temp, account, now_cursor);
            account.setNextCursor(now_cursor);
            accountService.updateById(account);
        }
        account.setNextCursor(null);
        log.info("ResThread -> run -> msg: 更新数据库");
        accountService.updateById(account);
    }


}